package com.emiage.ddutils;

import android.content.Context;
import android.content.Intent;
import android.hardware.camera2.params.Face;
import android.net.Uri;
import android.os.Environment;
import android.os.StatFs;
import android.text.TextUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * Created by LiJZ on 2016/7/20.
 */
public class FileUtils {

	public static final String ROOT_DIR = "LJZ";
	public static final String DOWNLOAD_DIR = "download";
	public static final String CACHE_DIR = "cache";
	public static final String ICON_DIR = "icon";

	/**
	 * 判断SD卡是否挂载
	 */
	public static boolean isSDCardAvailable() {
		if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 获取下载目录
	 */
	public static String getDownloadDir(Context context) {
		return getDir(DOWNLOAD_DIR, context);
	}

	/**
	 * 获取缓存目录
	 */
	public static String getCacheDir(Context context) {
		return getDir(CACHE_DIR, context);
	}

	/**
	 * 获取icon目录
	 */
	public static String getIconDir(Context context) {
		return getDir(ICON_DIR, context);
	}

	/**
	 * 获取应用目录，当SD卡存在时，获取SD卡上的目录，当SD卡不存在时，获取应用的cache目录
	 */
	public static String getDir(String name, Context context) {
		StringBuilder sb = new StringBuilder();
		if (isSDCardAvailable()) {
			sb.append(getExternalStoragePath());
		} else {
			sb.append(getCachePath(context));
		}
		sb.append(name);
		sb.append(File.separator);
		String path = sb.toString();
		if (createDirs(path)) {
			return path;
		} else {
			return null;
		}
	}

	/**
	 * 获取SD下的应用目录
	 */
	public static String getExternalStoragePath() {
		StringBuilder sb = new StringBuilder();
		sb.append(Environment.getExternalStorageDirectory().getAbsolutePath());
		sb.append(File.separator);
		sb.append(ROOT_DIR);
		sb.append(File.separator);
		return sb.toString();
	}

	/**
	 * 获取应用的cache目录
	 */
	public static String getCachePath(Context context) {
		File f = context.getApplicationContext().getCacheDir();
		if (null == f) {
			return null;
		} else {
			return f.getAbsolutePath() + "/";
		}
	}

	/**
	 * 根据路径创建文件
	 *
	 * @param filePath
	 * @return
	 */
	public static File createFile(String filePath) {
		File file = new File(filePath);

		if (!file.getParentFile().exists())
			file.getParentFile().mkdirs();

		return file;
	}

	/**
	 * 在指定文件夹创建文件
	 *
	 * @param dir
	 * @param fileName
	 * @return
	 */
	public static File createFile(File dir, String fileName) {
		File file = new File(dir, fileName);

		if (!dir.exists())
			dir.mkdirs();

		return file;
	}

	/**
	 * 创建文件夹
	 */
	public static boolean createDirs(String dirPath) {
		File file = new File(dirPath);
		if (!file.exists() || !file.isDirectory()) {
			return file.mkdirs();
		}
		return true;
	}

	/**
	 * 复制文件，可以选择是否删除源文件
	 */
	public static boolean copyFile(String srcPath, String destPath, boolean deleteSrc) {
		File srcFile = new File(srcPath);
		File destFile = new File(destPath);
		return copyFile(srcFile, destFile, deleteSrc);
	}

	/**
	 * 复制文件，可以选择是否删除源文件
	 *
	 * @param sourceFile 源文件
	 * @param targetFile
	 * @param deleteSrc  是否要删除源文件
	 * @throws IOException
	 */
	public static boolean copyFile(File sourceFile, File targetFile, boolean deleteSrc) {
		if (!sourceFile.exists() || !sourceFile.isFile()) {
			return false;
		}
		BufferedInputStream inBuff = null;
		BufferedOutputStream outBuff = null;
		try {
			// 新建文件输入流并对它进行缓冲
			inBuff = new BufferedInputStream(new FileInputStream(sourceFile));

			// 新建文件输出流并对它进行缓冲
			outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));

			// 缓冲数组
			byte[] b = new byte[1024 * 5];
			int len;
			while ((len = inBuff.read(b)) != -1) {
				outBuff.write(b, 0, len);
			}
			// 刷新此缓冲的输出流
			outBuff.flush();
			if (deleteSrc) {
				sourceFile.delete();
			}
		} catch (IOException e) {
			return false;
		} finally {
			// 关闭流
			IOUtils.close(inBuff);
			IOUtils.close(outBuff);
		}
		return true;
	}

	/**
	 * 复制文件通过流
	 *
	 * @param inBuff
	 * @param targetFile
	 * @throws IOException
	 */
	public static boolean copyFileByIO(InputStream inBuff, File targetFile) {
		BufferedOutputStream outBuff = null;
		try {
			// 新建文件输出流并对它进行缓冲
			outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));

			// 缓冲数组
			byte[] b = new byte[1024 * 5];
			int len;
			while ((len = inBuff.read(b)) != -1) {
				outBuff.write(b, 0, len);
			}
			// 刷新此缓冲的输出流
			outBuff.flush();
		} catch (IOException e) {
			return false;
		} finally {
			// 关闭流
			IOUtils.close(inBuff);
			IOUtils.close(outBuff);
		}
		return true;
	}

	/**
	 * 资产目录复制入项目filesDir目录
	 *
	 * @param context 上下文
	 * @param name    文件名
	 */
	public static boolean copyAssetsToFilesDir(Context context, String name) {
		InputStream myInput = null;
		try {
			myInput = context.getAssets().open(name);
			File dataFolder = context.getFilesDir();
			File jar = new File(dataFolder.getAbsolutePath() + "/" + name);
			return FileUtils.copyFileByIO(myInput, jar);
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 复制文件夹
	 *
	 * @param sourceDir
	 * @param targetDir
	 * @throws IOException
	 */
	public static void copyDirectiory(String sourceDir, String targetDir) {
		// 新建目标目录
		(new File(targetDir)).mkdirs();
		// 获取源文件夹当前下的文件或目录
		File[] file = (new File(sourceDir)).listFiles();
		for (int i = 0; i < file.length; i++) {
			if (file[i].isFile()) {
				// 源文件
				File sourceFile = file[i];
				// 目标文件
				File targetFile = new File(new File(targetDir).getAbsolutePath() + File.separator + file[i].getName());
				copyFile(sourceFile, targetFile, false);
			}
			if (file[i].isDirectory()) {
				// 准备复制的源文件夹
				String dir1 = sourceDir + "/" + file[i].getName();
				// 准备复制的目标文件夹
				String dir2 = targetDir + "/" + file[i].getName();
				copyDirectiory(dir1, dir2);
			}
		}
	}

	/**
	 * 删除一个目录下的所有文件
	 *
	 * @param filepath
	 * @throws IOException
	 */
	public static void del(String filepath) {
		File f = new File(filepath);// 定义文件路径
		if (f.exists() && f.isDirectory()) {// 判断是文件还是目录
			if (f.listFiles().length == 0) {// 若目录下没有文件则直接删除
				f.delete();
			} else {// 若有则把文件放进数组，并判断是否有下级目录
				File delFile[] = f.listFiles();
				int i = f.listFiles().length;
				for (int j = 0; j < i; j++) {
					if (delFile[j].isDirectory()) {
						del(delFile[j].getAbsolutePath());// 递归调用del方法并取得子目录路径
					}
					delFile[j].delete();// 删除文件
				}
			}
		}
	}


	/**
	 * 文件转成字节数组,必要时可以转换成字符串
	 *
	 * @param path
	 * @return byte[]
	 * @throws IOException
	 */
	public static byte[] readFileToBytes(String path) throws IOException {
		byte[] b = null;
		InputStream is = null;
		File f = new File(path);
		try {
			is = new FileInputStream(f);
			b = new byte[(int) f.length()];
			is.read(b);
		} finally {
			if (is != null)
				is.close();
		}
		return b;
	}

	/**
	 * 将byte写入文件中
	 *
	 * @param fileByte
	 * @param filePath
	 * @throws IOException
	 */
	public static boolean byteToFile(byte[] fileByte, String filePath) throws IOException {
		OutputStream os = null;
		try {
			os = new FileOutputStream(new File(filePath));
			os.write(fileByte);
			os.flush();
		} catch (IOException e) {
			LogUtils.error(e);
			return false;
		} finally {
			if (os != null)
				os.close();
		}
		return true;
	}

	/**
	 * 判断文件是否可写
	 */
	public static boolean isWriteable(String path) {
		try {
			if (TextUtils.isEmpty(path)) {
				return false;
			}
			File f = new File(path);
			return f.exists() && f.canWrite();
		} catch (Exception e) {
			LogUtils.error(e);
			return false;
		}
	}

	/**
	 * 修改文件的权限,例如"777"等
	 */
	public static void chmod(String path, String mode) {
		try {
			String command = "chmod " + mode + " " + path;
			Runtime runtime = Runtime.getRuntime();
			runtime.exec(command);
		} catch (Exception e) {
			LogUtils.error(e);
		}
	}

	/**
	 * 把数据写入文件
	 *
	 * @param is       数据流
	 * @param path     文件路径
	 * @param recreate 如果文件存在，是否需要删除重建
	 * @return 是否写入成功
	 */
	public static boolean writeFile(InputStream is, String path, boolean recreate) {
		boolean res = false;
		File f = new File(path);
		FileOutputStream fos = null;
		try {
			if (recreate && f.exists()) {
				f.delete();
			}
			if (!f.exists() && null != is) {
				File parentFile = new File(f.getParent());
				parentFile.mkdirs();
				int count = -1;
				byte[] buffer = new byte[1024];
				fos = new FileOutputStream(f);
				while ((count = is.read(buffer)) != -1) {
					fos.write(buffer, 0, count);
				}
				res = true;
			}
		} catch (Exception e) {
			LogUtils.error(e);
		} finally {
			IOUtils.close(fos);
			IOUtils.close(is);
		}
		return res;
	}

	/**
	 * 把字符串数据写入文件
	 *
	 * @param content 需要写入的字符串
	 * @param path    文件路径名称
	 * @param append  是否以添加的模式写入
	 * @return 是否写入成功
	 */
	public static boolean writeFile(byte[] content, String path, boolean append) {
		boolean res = false;
		File f = new File(path);
		RandomAccessFile raf = null;
		try {
			if (f.exists()) {
				if (!append) {
					f.delete();
					f.createNewFile();
				}
			} else {
				f.createNewFile();
			}
			if (f.canWrite()) {
				raf = new RandomAccessFile(f, "rw");
				raf.seek(raf.length());
				raf.write(content);
				res = true;
			}
		} catch (Exception e) {
			LogUtils.error(e);
		} finally {
			IOUtils.close(raf);
		}
		return res;
	}

	/**
	 * 把字符串数据写入文件
	 *
	 * @param content 需要写入的字符串
	 * @param path    文件路径名称
	 * @param append  是否以添加的模式写入
	 * @return 是否写入成功
	 */
	public static boolean writeFile(String content, String path, boolean append) {
		return writeFile(content.getBytes(), path, append);
	}

	/**
	 * 把键值对写入文件
	 *
	 * @param filePath 文件路径
	 * @param key      键
	 * @param value    值
	 * @param comment  该键值对的注释
	 */
	public static void writeProperties(String filePath, String key, String value, String comment) {
		if (TextUtils.isEmpty(key) || TextUtils.isEmpty(filePath)) {
			return;
		}
		FileInputStream fis = null;
		FileOutputStream fos = null;
		File f = new File(filePath);
		try {
			if (!f.exists() || !f.isFile()) {
				f.createNewFile();
			}
			fis = new FileInputStream(f);
			Properties p = new Properties();
			p.load(fis);// 先读取文件，再把键值对追加到后面
			p.setProperty(key, value);
			fos = new FileOutputStream(f);
			p.store(fos, comment);
		} catch (Exception e) {
			LogUtils.error(e);
		} finally {
			IOUtils.close(fis);
			IOUtils.close(fos);
		}
	}

	/**
	 * 根据值读取
	 */
	public static String readProperties(String filePath, String key, String defaultValue) {
		if (TextUtils.isEmpty(key) || TextUtils.isEmpty(filePath)) {
			return null;
		}
		String value = null;
		FileInputStream fis = null;
		File f = new File(filePath);
		try {
			if (!f.exists() || !f.isFile()) {
				f.createNewFile();
			}
			fis = new FileInputStream(f);
			Properties p = new Properties();
			p.load(fis);
			value = p.getProperty(key, defaultValue);
		} catch (IOException e) {
			LogUtils.error(e);
		} finally {
			IOUtils.close(fis);
		}
		return value;
	}

	/**
	 * 把字符串键值对的map写入文件
	 */
	public static void writeMap(String filePath, Map<String, String> map, boolean append, String comment) {
		if (map == null || map.size() == 0 || TextUtils.isEmpty(filePath)) {
			return;
		}
		FileInputStream fis = null;
		FileOutputStream fos = null;
		File f = new File(filePath);
		try {
			if (!f.exists() || !f.isFile()) {
				f.createNewFile();
			}
			Properties p = new Properties();
			if (append) {
				fis = new FileInputStream(f);
				p.load(fis);// 先读取文件，再把键值对追加到后面
			}
			p.putAll(map);
			fos = new FileOutputStream(f);
			p.store(fos, comment);
		} catch (Exception e) {
			LogUtils.error(e);
		} finally {
			IOUtils.close(fis);
			IOUtils.close(fos);
		}
	}

	/**
	 * 把字符串键值对的文件读入map
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	public static Map<String, String> readMap(String filePath, String defaultValue) {
		if (TextUtils.isEmpty(filePath)) {
			return null;
		}
		Map<String, String> map = null;
		FileInputStream fis = null;
		File f = new File(filePath);
		try {
			if (!f.exists() || !f.isFile()) {
				f.createNewFile();
			}
			fis = new FileInputStream(f);
			Properties p = new Properties();
			p.load(fis);
			map = new HashMap<String, String>((Map) p);// 因为properties继承了map，所以直接通过p来构造一个map
		} catch (Exception e) {
			LogUtils.error(e);
		} finally {
			IOUtils.close(fis);
		}
		return map;
	}

	/**
	 * 判断文件是否存在
	 *
	 * @param filePath
	 * @return
	 */
	public static boolean isExits(String filePath) {
		if (TextUtils.isEmpty(filePath))
			return false;

		File file = createFile(filePath);
		if (file.exists())
			return true;
		else
			return false;
	}

	/**
	 * 格式化文件大小
	 *
	 * @param file
	 * @return
	 */
	public static String getFileSize(File file) {
		if (!file.exists())
			return "";

		return getFileSize(file.length());
	}

	/**
	 * 格式化文件大小
	 *
	 * @param fileS
	 * @return
	 */
	public static String getFileSize(long fileS) {
		DecimalFormat df = new DecimalFormat("0.00");
		String fileSizeString = "";

		if (fileS < 1024)
			fileSizeString = df.format((double) fileS) + "B";
		else if (fileS < 1048576)
			fileSizeString = df.format((double) fileS / 1024) + "K";
		else if (fileS < 1073741824)
			fileSizeString = df.format((double) fileS / 1048576) + "M";
		else
			fileSizeString = df.format((double) fileS / 1073741824) + "G";


		return fileSizeString;
	}

	public static Intent getIntent(String filePath) {
		File file = createFile(filePath);
		return getIntent(file);
	}

	public static Intent getIntent(File file) {
		if (!file.exists())
			return null;

		int iType = getFileType(file);
		String sType = getMIMEType(iType);

		Intent intent = null;
		Uri uri = Uri.fromFile(file);

		switch (iType) {
			case MIMEType.TYPE_TEXT:
				intent = new Intent("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			case MIMEType.TYPE_IMAGE:
				intent = new Intent("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			case MIMEType.TYPE_AUDIO:
				intent = new Intent("android.intent.action.VIEW");
				intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				intent.putExtra("oneshot", 0);
				intent.putExtra("configchange", 0);
				break;

			case MIMEType.TYPE_VIDEO:
				intent = new Intent("android.intent.action.VIEW");
				intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
				intent.putExtra("oneshot", 0);
				intent.putExtra("configchange", 0);
				break;

			case MIMEType.TYPE_APK:
				intent = new Intent();
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				intent.setAction(android.content.Intent.ACTION_VIEW);
				break;

			case MIMEType.TYPE_WEB:
				intent = new Intent("android.intent.action.VIEW");
				uri = Uri.parse(file.toString()).buildUpon()
						.encodedAuthority("com.android.htmlfileprovider")
						.scheme("content").encodedPath(file.toString()).build();
				break;

			case MIMEType.TYPE_WORD:
				intent = new Intent("android.intent.action.VIEW");
//			intent.setAction("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			case MIMEType.TYPE_EXCEL:
				intent = new Intent("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			case MIMEType.TYPE_PPT:
				intent = new Intent("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			case MIMEType.TYPE_PDF:
				intent = new Intent("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			case MIMEType.TYPE_CHM:
				intent = new Intent("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			case MIMEType.TYPE_ZIP:
				intent = new Intent("android.intent.action.VIEW");
				intent.addCategory("android.intent.category.DEFAULT");
				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				break;

			default:
				break;
		}

		intent.setDataAndType(uri, sType);

		return intent;
	}


	/**
	 * 获取MIME类型
	 **/
	public static String getMIMEType(String name) {

		int iType = getFileType(name);

		return getMIMEType(iType);
	}

	/**
	 * 获取MIME类型
	 **/
	public static String getMIMEType(int type) {

		String sType = "";

		switch (type) {
			case MIMEType.TYPE_TEXT:
				sType = "text";
				break;

			case MIMEType.TYPE_IMAGE:
				sType = "image";
				break;

			case MIMEType.TYPE_AUDIO:
				sType = "audio";
				break;

			case MIMEType.TYPE_VIDEO:
				sType = "video";
				break;

			case MIMEType.TYPE_APK:
				return "application/vnd.android.package-archive";

			case MIMEType.TYPE_WEB:
				return "text/html";

			case MIMEType.TYPE_WORD:
				return "application/msword";

			case MIMEType.TYPE_EXCEL:
				return "application/vnd.ms-excel";

			case MIMEType.TYPE_PPT:
				return "application/vnd.ms-powerpoint";

			case MIMEType.TYPE_PDF:
				return "application/pdf";

			case MIMEType.TYPE_CHM:
				return "application/x-chm";

			case MIMEType.TYPE_ZIP:
				return "application/x-zip-compressed";

			default:
				sType = "*";
				break;
		}

		sType += "/*";

		return sType;
	}

	public static int getFileType(File file) {

		String name = file.getName();

		return getFileType(name);
	}

	public static int getFileType(String fileName) {

		if (checkEnd(fileName, MIMEType.APK)) {
			return MIMEType.TYPE_APK;
		} else if (checkEndAmr(fileName)) {
			return MIMEType.TYPE_AMR;
		} else if (checkEnd(fileName, MIMEType.VIDEO)) {
			return MIMEType.TYPE_VIDEO;
		} else if (checkEnd(fileName, MIMEType.AUDIO)) {
			return MIMEType.TYPE_AUDIO;
		} else if (checkEndImage(fileName)) {
			return MIMEType.TYPE_IMAGE;
		} else if (checkEnd(fileName, MIMEType.TEXT)) {
			return MIMEType.TYPE_TEXT;
		} else if (checkEnd(fileName, MIMEType.WEB)) {
			return MIMEType.TYPE_WEB;
		} else if (checkEnd(fileName, MIMEType.WORD)) {
			return MIMEType.TYPE_WORD;
		} else if (checkEnd(fileName, MIMEType.EXCEL)) {
			return MIMEType.TYPE_EXCEL;
		} else if (checkEnd(fileName, MIMEType.PPT)) {
			return MIMEType.TYPE_PPT;
		} else if (checkEnd(fileName, MIMEType.PDF)) {
			return MIMEType.TYPE_PDF;
		} else if (checkEnd(fileName, MIMEType.ZIP)) {
			return MIMEType.TYPE_ZIP;
		} else {
			return MIMEType.TYPE_DEF;
		}
	}

	/**
	 * 判断文件扩展名
	 *
	 * @param fileName
	 * @param fileEndings
	 * @return
	 */
	public static boolean checkEnd(String fileName, String[] fileEndings) {
		if (TextUtils.isEmpty(fileName) || fileEndings == null)
			return false;

		fileName = fileName.toLowerCase().trim();

		for (String aEnd : fileEndings) {
			if (fileName.endsWith(aEnd))
				return true;
		}

		return false;
	}

	/**
	 * 判断文件是否为图片
	 *
	 * @param fileName
	 * @return
	 */
	public static boolean checkEndImage(String fileName) {
		return checkEnd(fileName, MIMEType.IMAGE);
	}

	/**
	 * 判断文件是否为音频文件
	 *
	 * @param fileName
	 * @return
	 */
	public static boolean checkEndAmr(String fileName) {
		return checkEnd(fileName, MIMEType.AMR);
	}

	/**
	 * 判断文件是否为视频文件
	 *
	 * @param fileName
	 * @return
	 */
	public static boolean checkEndVideo(String fileName) {
		return checkEnd(fileName, MIMEType.VIDEO);
	}

	/**
	 * 获取指定路径所在空间的剩余可用容量字节数，单位byte
	 *
	 * @param filePath
	 * @return 容量字节 SDCard可用空间，内部存储可用空间
	 */
	public static long getFreeBytes(String filePath) {
		// 如果是sd卡的下的路径，则获取sd卡可用容量
		if (filePath.startsWith(SDCardUtils.getSDCardPath())) {
			filePath = SDCardUtils.getSDCardPath();
		} else {// 如果是内部存储的路径，则获取内存存储的可用容量
			filePath = Environment.getDataDirectory().getAbsolutePath();
		}
		StatFs stat = new StatFs(filePath);
		long availableBlocks = (long) stat.getAvailableBlocks() - 4;
		return stat.getBlockSize() * availableBlocks;
	}
	/**
	 * 方法描述：获取文件时间戳
	 */
	public static long getFileTime(String dir, String fileName) {
		File file = new File(dir, fileName);
		return file.lastModified();
	}

	/**
	 * 方法描述：给文件加时间戳
	 */
	public static void updateFileTime(String dir, String fileName) {
		File file = new File(dir, fileName);
		long newModifiedTime = System.currentTimeMillis();
		file.setLastModified(newModifiedTime);
	}
}
